package com.lt.app;

import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 消息回调
 *
 * @author luotian
 */
public class NotificationCenter {

    private final Map<String, Map<WeakReference<Object>, String>> obseverList = new HashMap<>();

    public void sendNotification(String notificationName, Object obj) {
        Map<WeakReference<Object>, String> observersMap = obseverList
                .get(notificationName);
        if (observersMap != null) {

            Set<WeakReference<Object>> setObserver = observersMap.keySet();
            for (WeakReference<Object> observerPreference : setObserver) {

                if (observerPreference == null)
                    continue;
                Object observer = observerPreference.get();
                if (observer == null)
                    continue;

                String methodName = observersMap.get(observerPreference);
                Class<?> classObj = observer.getClass();
                if (methodName != null) {
                    try {
                        Method method = classObj
                                .getMethod(methodName, Object.class);
                        method.invoke(observer, obj);

                    } catch (SecurityException | InvocationTargetException | IllegalAccessException | IllegalArgumentException | NoSuchMethodException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }

        }
    }

    public void removeObserver(Object observer, String notificationName) {
        Map<WeakReference<Object>, String> currentObserversMap = obseverList
                .get(notificationName);
        if (currentObserversMap != null) {
            for (WeakReference<Object> weakObserver : currentObserversMap
                    .keySet()) {
                if (weakObserver != null) {
                    if (weakObserver.get() == observer) {

                        currentObserversMap.remove(weakObserver);
                        break;
                    }
                }
            }

            if (currentObserversMap.size() == 0) {
                obseverList.remove(notificationName);
            }

        }

    }

    public void removeObserver(Object observer) {
        for (String notificationName : obseverList.keySet()) {
            Map<WeakReference<Object>, String> observersMap = obseverList
                    .get(notificationName);

            if (observersMap != null) {
                for (WeakReference<Object> weakObserver : observersMap.keySet()) {
                    if (weakObserver != null) {
                        if (weakObserver.get() == observer) {

                            observersMap.remove(weakObserver);
                            break;
                        }
                    }
                }

                if (observersMap.size() == 0) {
                    obseverList.remove(notificationName);
                    break;
                }

            }

        }

    }

    public void addObserver(Object observer, String notificationName,
                            String methodName) {
        Map<WeakReference<Object>, String> currentObserversMap = obseverList
                .get(notificationName);
        if (currentObserversMap != null) {
            boolean hasObserver = false;
            for (WeakReference<Object> weakObserver : currentObserversMap
                    .keySet()) {
                if (weakObserver != null) {
                    if (weakObserver.get() == observer) {

                        currentObserversMap.remove(weakObserver);
                        currentObserversMap.put(weakObserver, methodName);
                        hasObserver = true;
                    }
                }
            }

            if (!hasObserver) {
                currentObserversMap.put(new WeakReference<>(observer),
                        methodName);
            }
        } else {
            Map<WeakReference<Object>, String> newObserversMap = new HashMap<>();
            newObserversMap.put(new WeakReference<>(observer),
                    methodName);
            obseverList.put(notificationName, newObserversMap);
        }
    }

}
